package graduation.project.utilities;

import graduation.project.body.OriginExpression;
import graduation.project.exception.NonExpressionException;

import java.util.regex.Pattern;

public class Utility {

	public static boolean checkExpressionValid(String exp) {

		// get rid of white space
		exp = exp.replaceAll("\\s", "");
		// Pattern p = Pattern.compile("[!!]|[!+]|[!)]|[++]|[(+]|[+)]");
		// Pattern p1 = Pattern.compile(".*[0-9]+.*");
		// Pattern p2 = Pattern.compile(".*!{2,}.*");
		// Pattern p3 = Pattern.compile(".*!\\+.*");
		// Pattern p4 = Pattern.compile(".*!\\).*");
		// Pattern p5 = Pattern.compile(".*\\+{2,}.*");
		// Pattern p6 = Pattern.compile(".*\\(\\+.*");
		// Pattern p7 = Pattern.compile(".*\\+\\).*");

		if (exp.length() == 0)
			return false;
		if (exp.charAt(0) == '+' || exp.charAt(0) == ')'
				|| exp.charAt(exp.length() - 1) == '+'
				|| exp.charAt(exp.length() - 1) == '!'
				|| exp.charAt(exp.length() - 1) == '(')
			return false;
		if (Pattern.matches(".*[0-9]+.*", exp))
			return false;
		if (Pattern.matches(".*!{2,}.*", exp))
			return false;
		if (Pattern.matches(".*!\\+.*", exp))
			return false;
		if (Pattern.matches(".*!\\).*", exp))
			return false;
		if (Pattern.matches(".*\\+{2,}.*", exp))
			return false;
		if (Pattern.matches(".*\\(\\+.*", exp))
			return false;
		if (Pattern.matches(".*\\+\\).*", exp))
			return false;

		int left = exp.replaceAll("[^(]", "").length();
		int right = exp.replaceAll("[^)]", "").length();
		if (left != right)
			return false;

		return true;
	}

	/**
	 * give a array, select log(|size|) items to construct a new array.
	 * 
	 * @param originArr
	 * @return
	 */
	public static int[] getSubLogArray(int[] originArr) {
		int subArrayLength;

		if (originArr == null)
			return null;
		if (originArr.length == 1)
			subArrayLength = 1;
		else
			subArrayLength = (int) Math.floor(Math.ceil(Math
					.log(originArr.length)
					/ Math.log(2)));

		int[] subArray = new int[subArrayLength];
		int[] indexForSub = new int[subArrayLength];
		for (int i = 0; i < subArrayLength; i++)
			indexForSub[i] = -1;

		int index = 0;
		int selected;
		while (index < subArrayLength) {
			boolean inArray = false;
			selected = (int) (Math.random() * (originArr.length));
			for (int i = 0; i < index; i++)
				if (indexForSub[i] == selected) {
					inArray = true;
					break;
				}
			if (inArray == true)
				continue;

			indexForSub[index] = selected;
			subArray[index] = originArr[selected];
			index++;
		}
		return subArray;
	}

	/**
	 * 1 represents the corresponding item is selected, 0 is not.
	 * 
	 * @param containerNum
	 * @param selectNum
	 * @return
	 */
	public static int[] getORAllCombin(int containerNum, int selectNum) {
		if (containerNum <= 0 || selectNum < 0 || selectNum > containerNum)
			return null;

		int[] result = new int[getCombin(containerNum, selectNum)];
		for (int i = 0; i < result.length; i++)
			result[i] = -1;

		int index = 0;
		String temp; // used to deal with String;
		for (int i = 0; i < (int) Math.floor(Math.pow(2, containerNum)); i++) {
			temp = Integer.toBinaryString(i);
			temp = temp.replaceAll("0", "");
			if (temp.length() == selectNum) {
				result[index++] = i;
				if (index >= result.length)
					break;
			}

		}
		return result;
	}

	/**
	 * 0 represents the corresponding item is selected, 1 is not.
	 * 
	 * @param containerNum
	 * @param selectNum
	 * @return
	 */
	public static int[] getANDAllCombin(int containerNum, int selectNum) {
		if (containerNum <= 0 || selectNum < 0 || selectNum > containerNum)
			return null;

		int[] result = new int[getCombin(containerNum, selectNum)];
		for (int i = 0; i < result.length; i++)
			result[i] = -1;

		int index = 0;
		String temp; // used to deal with String;
		StringBuffer s = new StringBuffer();
		for (int i = (int) Math.floor(Math.pow(2, containerNum)) - 1; i >= 0; i--) {
			temp = Integer.toBinaryString(i);

			for (int j = 0; j < containerNum - temp.length(); j++)
				s.append('0');
			temp = s.toString() + temp;
			s.delete(0, s.length());

			temp = temp.replaceAll("1", "");
			if (temp.length() == selectNum) {
				System.out.println("index:" + index);
				result[index++] = i;
				if (index >= result.length)
					break;
			}

		}
		return result;
	}

	/**
	 * compute (i, n)
	 * 
	 * @param containerNum
	 * @param select
	 * @return
	 */
	public static int getCombin(int containerNum, int select) {
		if (containerNum <= 0 || select < 0 || select > containerNum)
			return -1;

		if (select == 0)
			return 1;
		if (select > containerNum / 2)
			select = containerNum - select;
		int result = 1;
		for (int i = 0; i < select; i++) {
			result *= containerNum;
			containerNum--;
		}
		for (int i = 1; i <= select; i++)
			result = result / i;

		return result;
	}

	/**
	 * compute the distance of a cell and a term.
	 * 
	 * @param term
	 * @param cell
	 * @param model
	 * @return
	 */
	public static int getDistanceofCelltoTerm(String term, int cell,
			String model) {

		int result = 0;
		String cellStr = Integer.toBinaryString(cell);
		StringBuffer cellM = new StringBuffer();
		for (int i = 0; i < model.length() - cellStr.length(); i++)
			cellM.append('0');
		cellM.append(cellStr);

		char lit;
		for (int i = 0; i < term.length(); i++) {
			lit = term.charAt(i);
			if (lit == '!') {
				if (cellM.charAt(model.indexOf(term.charAt(i + 1))) == '1') {
					result++;
				}
				i++;
			}
			if ((lit != '!') && (cellM.charAt(model.indexOf(lit)) == '0')) {
				result++;
			}
		}
		return result;
	}

	/**
	 * get two cells which are the max different in array
	 * 
	 * @param arr
	 * @return
	 */
	public static int[] getMaxDifferCells(int[] arr) {

		if (arr == null)
			return null;

		int[] result = new int[2];
		int select1 = 0;
		int select2 = 0;
		int differ = 0;

		String temp;
		for (int i = 0; i < arr.length; i++) {
			for (int j = i + 1; j < arr.length; j++) {
				temp = Integer.toBinaryString(
						(arr[i] | arr[j]) - (arr[i] & arr[j])).replaceAll("0",
						"");
				if (temp.length() > differ) {
					differ = temp.length();
					select1 = arr[i];
					select2 = arr[j];
				}
			}
		}
		result[0] = select1;
		result[1] = select2;
		return result;
	}

	/**
	 * 
	 * @param cell
	 * @param model
	 * @return
	 */
	public static String intoString(int cell, String model) {

		StringBuffer cellStr = new StringBuffer();
		int cellLen = Integer.toBinaryString(cell).length();
		for (int i = 0; i < model.length() - cellLen; i++)
			cellStr.append('0');
		cellStr.append(Integer.toBinaryString(cell));

		StringBuffer result = new StringBuffer();
		for (int i = 0; i < cellStr.length(); i++) {
			if (cellStr.charAt(i) == '0')
				result.append('!');
			result.append(model.charAt(i));
		}
		return result.toString();
	}

	public static void main(String[] args) {
		/*
		 * String exp = "!ef!g!a(bc + !bd)"; if(checkExpressionValid(exp))
		 * System.out.println("valid"); else System.out.println("Invalid");
		 */
		System.out.println(getDistanceofCelltoTerm("ab!cd", 0, "abcd"));
		System.out
				.println("a!d+a!e+a!g!i!k+a!h!lg+a!h!k+aig!l+aig!k+ai!h!g+!g!i!kb+!g!i!kc!m+!i!kf+!h!lgb+!h!lgc!m+!h!kb+!h!kc!m+gf+ig!lb+ig!lc!m+ig!kb+ig!kc!m+i!h!gb+i!h!gc!m+i!hf"
						.split("\\+").length);
		String exp = "!(ab)(d!e!f + !de!f)(ac(d + e)h + a(d + e)!h + b(e + f))";
		try {
			OriginExpression or = new OriginExpression(exp);
			System.out.println("exp: " + exp);
			System.out.println("idnf: " + or.getIDNF());
		} catch (NonExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
